package com.lcm.weam.aspect;

import com.lcm.weam.annotation.Decrypt;
import com.lcm.weam.annotation.Encrypt;
import com.lcm.weam.entity.resp.Result;
import com.lcm.weam.util.ApiSecurityUtil;
import com.lcm.weam.util.JsonUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * api数据加密的切面类
 */
@Aspect
@Component
public class CipherAspect {

    //对所有controller下的接口做切面
    @Pointcut(value = "execution(public * com.lcm.weam.controller.*.*.*(..))")
    public void cipherAspect() {
    }

    //环绕通知
    @Around(value = "cipherAspect()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取request对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String httpMethod = request.getMethod().toLowerCase(); //http请求方法
        Method method = ((MethodSignature) pjp.getSignature()).getMethod(); //目标method
        Annotation[] annotations = method.getAnnotations(); //获取方法上的注解
        Object[] args = pjp.getArgs(); //方法参数
        //判断注解
        boolean hasDecrypt = false; //@Decrypt需要对参数进行解密
        boolean hasEncrypt = false; //@Encrypt表示需要对返回值加密
        for (Annotation annotation : annotations) {
            if (annotation.annotationType() == Decrypt.class) {
                hasDecrypt = true;
            }
            if (annotation.annotationType() == Encrypt.class) {
                hasEncrypt = true;
            }
        }
        //执行方法前解密请求
        if("post".equals(httpMethod) && hasDecrypt){
            //api解密
            String decrypt = ApiSecurityUtil.decrypt();
            //注：controller方法需要是实体接参且第一个参数就是
            if(args.length > 0){
                args[0] = JsonUtil.parse(decrypt, args[0].getClass());
            }
        }
        //方法执行
        Result o = (Result) pjp.proceed(args);
        //返回结果加密
        if (hasEncrypt){
            //api加密，转json字符串并转成Object对象，设置到Result中并赋值给返回值o
            o.setData(ApiSecurityUtil.encrypt(o.getData()));
        }
        return o;
    }
}
